package cn.qianxun.meta.dict.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.qianxun.meta.common.core.dto.RowsData;
import cn.qianxun.meta.common.core.web.vo.RemoveLongDTO;
import cn.qianxun.meta.dict.dto.AddDictDataDTO;
import cn.qianxun.meta.dict.dto.QueryDictDataDTO;
import cn.qianxun.meta.dict.entity.SysDictData;
import cn.qianxun.meta.dict.entity.SysDictType;
import cn.qianxun.meta.dict.mapper.SysDictTypeMapper;
import cn.qianxun.meta.dict.service.ISysDictDataService;
import cn.qianxun.meta.dict.util.DictUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import cn.qianxun.meta.common.core.constant.Constants;
import cn.qianxun.meta.common.core.exception.ServiceException;
import cn.qianxun.meta.common.core.manager.AsyncManager;
import cn.qianxun.meta.common.satoken.utils.LoginHelper;
import cn.qianxun.meta.dict.mapper.SysDictDataMapper;
import cn.qianxun.meta.dict.vo.SysDictDataVO;
import cn.qianxun.meta.dict.vo.SysDictTypeItemsVO;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 字典数据表 服务实现类
 * </p>
 *
 * @author fuzhilin
 * @since 2023/08/24
 */
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class SysDictDataServiceImpl extends ServiceImpl<SysDictDataMapper, SysDictData> implements ISysDictDataService {
    private final SysDictDataMapper sysDictDataMapper;
    private final SysDictTypeMapper sysDictTypeMapper;

    @Override
    public RowsData<SysDictDataVO> selectDictDataList(QueryDictDataDTO dto) {
        Page<Object> page = PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
        List<SysDictDataVO> list = sysDictDataMapper.selectDictDataList(dto);
        return new RowsData<SysDictDataVO>(list, page.getTotal(), dto.getPageNum());
    }

    @Override
    public SysDictDataVO details(Long dictCode) {
        SysDictDataVO dataDTO = new SysDictDataVO();
        SysDictData dictData = sysDictDataMapper.selectById(dictCode);
        if (ObjectUtil.isNull(dictData)) {
            throw new ServiceException("所查数据，请检查参数是否有误！");
        }
        BeanUtils.copyProperties(dictData, dataDTO);
        return dataDTO;
    }

    @Override
    public List<SysDictDataVO> selectDictDataByType(String dictType) {
        List<SysDictData> dataList = sysDictDataMapper.selectList(new LambdaQueryWrapper<SysDictData>().eq(SysDictData::getDictType, dictType).orderByAsc(SysDictData::getDictSort));
        List<SysDictDataVO> list = dataList.stream().map(data -> {
            SysDictDataVO dataDTO = new SysDictDataVO();
            BeanUtils.copyProperties(data, dataDTO);
            return dataDTO;

        }).collect(Collectors.toList());
        return list;
    }


    @Override
    public List<SysDictTypeItemsVO> dictDateByParentType(String dictType) {
        List<SysDictData> dataList = sysDictDataMapper.selectList(new LambdaQueryWrapper<SysDictData>().eq(SysDictData::getDictType, dictType));
        List<SysDictTypeItemsVO> list = dataList.stream().map(data -> {
            // 查库数据最大是10个，性能可容忍。
            List<SysDictData> itemDataList = sysDictDataMapper.selectList(new LambdaQueryWrapper<SysDictData>().eq(SysDictData::getDictType, data.getDictValue()).orderByAsc(SysDictData::getDictSort));
            List<SysDictDataVO> itemList = itemDataList.stream().map(dictData -> {
                SysDictDataVO dataDTO = new SysDictDataVO();
                BeanUtils.copyProperties(dictData, dataDTO);
                return dataDTO;
            }).collect(Collectors.toList());

            SysDictTypeItemsVO dataDTO = new SysDictTypeItemsVO();
            dataDTO.setDictId(data.getDictCode());
            dataDTO.setDictName(data.getDictLabel());
            dataDTO.setDictType(data.getDictType());
            dataDTO.setItems(itemList);
            return dataDTO;

        }).collect(Collectors.toList());
        return list;
    }


    @Override
    public void addDictData(AddDictDataDTO dto) {
        SysDictData dictData = new SysDictData();
        BeanUtils.copyProperties(dto, dictData);
        dictData.setCreateBy(LoginHelper.getUserName());
        dictData.setCreateTime(new Date());
        List<SysDictData> list = sysDictDataMapper.selectList(new QueryWrapper<SysDictData>().lambda()
                .eq(SysDictData::getDictType, dictData.getDictType())
                .eq(SysDictData::getDictLabel, dictData.getDictLabel()));
        if (!CollectionUtils.isEmpty(list)) {
            throw new ServiceException("【" + dictData.getDictLabel() + "】" + "名称已存在，请勿重复添加");
        }
        List<SysDictData> valueList = sysDictDataMapper.selectList(new QueryWrapper<SysDictData>().lambda()
                .eq(SysDictData::getDictType, dictData.getDictType())
                .eq(SysDictData::getDictValue, dictData.getDictValue()));
        if (!CollectionUtils.isEmpty(valueList)) {
            throw new ServiceException("【" + dictData.getDictValue() + "】" + "值已存在，请勿重复添加");
        }
        int row = sysDictDataMapper.insert(dictData);
        if (row > 0) {
            DictUtils.clearDictCache();
            initdictdata();
        }
    }

    @Override
    public void editDictData(AddDictDataDTO dto) {
        SysDictData dictData = new SysDictData();
        BeanUtils.copyProperties(dto, dictData);
        dictData.setUpdateBy(LoginHelper.getUserName());
        dictData.setUpdateTime(new Date());
        int row = sysDictDataMapper.updateById(dictData);
        if (row > 0) {
            DictUtils.clearDictCache();
            initdictdata();
        }
    }

    @Override
    public void deleteDictDataByIds(RemoveLongDTO vo) {
        for (Long dictCode : vo.getRemoveIdList()) {
            SysDictData dictData = sysDictDataMapper.selectOne(new QueryWrapper<SysDictData>().lambda()
                    .eq(SysDictData::getDictCode, dictCode));
            if (ObjectUtil.isNull(dictData)) {
                throw new ServiceException("所删数据，请检查参数是否有误！");
            }
            if (Constants.STATUS_NORMAL.equals(dictData.getStatus())) {
                throw new ServiceException(dictData.getDictLabel() + "正在使用,不可删除");
            }
        }
        int row = sysDictDataMapper.deleteDictDataByIds(vo.getRemoveIdList());
        if (row > 0) {
            DictUtils.clearDictCache();
            initdictdata();
        }
    }

    @Override
    public Map<String, List<SysDictDataVO>> dictList() {
        List<SysDictDataVO> sysDictListDtos = sysDictTypeMapper.dictList();
        Set<String> dictTypes = sysDictListDtos.stream().map(SysDictDataVO::getDictType).collect(Collectors.toSet());
        Map<String, List<SysDictDataVO>> map = new HashMap<>(dictTypes.size());
        List<SysDictDataVO> dtos;
        for (String dictType : dictTypes) {
            dtos = sysDictListDtos.stream().filter(sysDictListDTO -> sysDictListDTO.getDictType().equals(dictType)).collect(Collectors.toList());
            map.put(dictType, dtos);
        }
        return map;
    }

    @Override
    public SysDictData getDictData(String dictType, String dictValue) {
        SysDictData sysDictData = sysDictDataMapper.selectOne(new LambdaQueryWrapper<SysDictData>().eq(SysDictData::getDictType, dictType).eq(SysDictData::getDictValue, dictValue).orderByDesc(SysDictData::getCreateTime).last("limit 1"));
        return sysDictData;
    }


    /**
     * 清空后异步加载一下所有得字典缓存
     */
    public void initdictdata() {
        AsyncManager.me().execute(new TimerTask() {
            @Override
            public void run() {
                List<SysDictType> dictTypeList = sysDictTypeMapper.selectList(new QueryWrapper<>());
                for (SysDictType dictType : dictTypeList) {
                    List<SysDictData> dictDatas = sysDictDataMapper.selectList(new LambdaQueryWrapper<SysDictData>().eq(SysDictData::getDictType, dictType.getDictType()));
                    if (!CollectionUtils.isEmpty(dictDatas)) {
                        for (SysDictData data : dictDatas) {
                            DictUtils.setDictLabelCache(Constants.SYS_DICT_LABEL_KEY + data.getDictType() + ":" + data.getDictValue(), data.getDictLabel());
                        }
                    }
                    DictUtils.setDictCache(dictType.getDictType(), dictDatas);
                }
            }
        });
    }
}
